<?php

namespace fastphp;

/**
 * 数据验证类
 * 提供数据验证功能，支持多种验证规则
 */
class Validator
{
    /**
     * 验证错误信息
     * @var array
     */
    protected array $_errors = [];

    /**
     * 自定义验证规则
     * @var array
     */
    protected array $_customRules = [];

    /**
     * 验证数据是否符合规则
     * 
     * @param array $data 要验证的数据
     * @param array $rules 验证规则数组
     * @return bool 验证是否通过
     */
    public function validate(array $data, array $rules): bool
    {
        $this->_errors = [];

        foreach ($rules as $field => $rule) {
            // 如果是required规则，但字段不存在，直接报错
            if (strpos($rule, 'required') !== false && !isset($data[$field])) {
                $this->_errors[$field] = "{$field}不能为空";
                continue;
            }

            // 如果字段不存在且不是required规则，跳过验证
            if (!isset($data[$field]) && strpos($rule, 'required') === false) {
                continue;
            }

            // 分割规则
            $ruleArray = explode('|', $rule);
            foreach ($ruleArray as $singleRule) {
                if (!$this->validateRule($field, $data[$field], $singleRule)) {
                    break;
                }
            }
        }

        return empty($this->_errors);
    }

    /**
     * 验证单个规则
     * 
     * @param string $field 字段名
     * @param mixed $value 字段值
     * @param string $rule 验证规则
     * @return bool 验证是否通过
     */
    protected function validateRule(string $field, $value, string $rule): bool
    {
        // 检查是否是自定义规则
        if (isset($this->_customRules[$rule])) {
            $callback = $this->_customRules[$rule];
            if (!$callback($value)) {
                $this->_errors[$field] = "{$field}不满足自定义验证规则";
                return false;
            }
            return true;
        }

        // 检查是否是带参数的规则
        if (strpos($rule, ':') !== false) {
            [$ruleName, $params] = explode(':', $rule, 2);
            
            switch ($ruleName) {
                case 'min':
                    if (mb_strlen($value) < $params) {
                        $this->_errors[$field] = "{$field}长度不能小于{$params}";
                        return false;
                    }
                    break;
                case 'max':
                    if (mb_strlen($value) > $params) {
                        $this->_errors[$field] = "{$field}长度不能大于{$params}";
                        return false;
                    }
                    break;
                case 'between':
                    [$min, $max] = explode(',', $params);
                    $length = mb_strlen($value);
                    if ($length < $min || $length > $max) {
                        $this->_errors[$field] = "{$field}长度必须在{$min}到{$max}之间";
                        return false;
                    }
                    break;
                case 'regex':
                    if (!preg_match($params, $value)) {
                        $this->_errors[$field] = "{$field}格式不正确";
                        return false;
                    }
                    break;
                case 'in':
                    $allowed = explode(',', $params);
                    if (!in_array($value, $allowed)) {
                        $this->_errors[$field] = "{$field}必须是以下值之一: " . implode(', ', $allowed);
                        return false;
                    }
                    break;
                case 'numeric':
                    if (!is_numeric($value)) {
                        $this->_errors[$field] = "{$field}必须是数字";
                        return false;
                    }
                    break;
                case 'min_value':
                    if (!is_numeric($value) || $value < $params) {
                        $this->_errors[$field] = "{$field}必须大于等于{$params}";
                        return false;
                    }
                    break;
                case 'max_value':
                    if (!is_numeric($value) || $value > $params) {
                        $this->_errors[$field] = "{$field}必须小于等于{$params}";
                        return false;
                    }
                    break;
                default:
                    // 不支持的规则
                    break;
            }
            return true;
        }

        // 不带参数的规则
        switch ($rule) {
            case 'required':
                if (empty($value) && $value !== '0' && $value !== 0) {
                    $this->_errors[$field] = "{$field}不能为空";
                    return false;
                }
                break;
            case 'email':
                if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
                    $this->_errors[$field] = "{$field}必须是有效的邮箱地址";
                    return false;
                }
                break;
            case 'url':
                if (!filter_var($value, FILTER_VALIDATE_URL)) {
                    $this->_errors[$field] = "{$field}必须是有效的URL";
                    return false;
                }
                break;
            case 'numeric':
                if (!is_numeric($value)) {
                    $this->_errors[$field] = "{$field}必须是数字";
                    return false;
                }
                break;
            case 'integer':
                if (!filter_var($value, FILTER_VALIDATE_INT)) {
                    $this->_errors[$field] = "{$field}必须是整数";
                    return false;
                }
                break;
            case 'boolean':
                if (!is_bool($value) && $value !== 'true' && $value !== 'false' && $value !== '1' && $value !== '0' && $value !== 1 && $value !== 0) {
                    $this->_errors[$field] = "{$field}必须是布尔值";
                    return false;
                }
                break;
            case 'array':
                if (!is_array($value)) {
                    $this->_errors[$field] = "{$field}必须是数组";
                    return false;
                }
                break;
            case 'alpha':
                if (!preg_match('/^[a-zA-Z]+$/', $value)) {
                    $this->_errors[$field] = "{$field}只能包含字母";
                    return false;
                }
                break;
            case 'alphanumeric':
                if (!preg_match('/^[a-zA-Z0-9]+$/', $value)) {
                    $this->_errors[$field] = "{$field}只能包含字母和数字";
                    return false;
                }
                break;
            default:
                // 不支持的规则
                break;
        }

        return true;
    }

    /**
     * 获取验证错误信息
     * 
     * @return array 错误信息数组
     */
    public function getErrors(): array
    {
        return $this->_errors;
    }

    /**
     * 添加自定义验证规则
     * 
     * @param string $name 规则名称
     * @param callable $callback 验证回调函数
     * @return $this
     */
    public function addRule(string $name, callable $callback): self
    {
        $this->_customRules[$name] = $callback;
        return $this;
    }

    /**
     * 静态创建验证实例
     * 
     * @return self 验证实例
     */
    public static function make(): self
    {
        return new self();
    }
}